#include "./server.h"

int main(int argc, char const *argv[])
{
	//1.数据库初始化
	sqlite3 *sql_db=proc_init();
	//检验命令行参数个数
    if (3 != argc)
    {
        printf("Usage : %s <IP> <PORT>\n", argv[0]);
        exit(-1);
    }
	//3. 创建套接字-填充服务器网络信息结构体-绑定-监听
    int sockfd = socket_bind_listen(argv);

	//4. 用来保存 客户端 信息的结构体
    struct sockaddr_in client_addr;
    memset(&client_addr, 0, sizeof(client_addr));
    socklen_t client_addr_len = sizeof(client_addr);

	pid_t pid;	// 进程 
	int accept_fd;
	
	while (1)
	{
		//阻塞等待客户端连接--一旦有客户端连接就会解除阻塞
		accept_fd=accept(sockfd,(struct sockaddr *)&client_addr, &client_addr_len);
		if (-1==accept_fd)	ERRLOG("accept error");
		/* inet_ntoa 32位网络字节序二进制地址转换成点分十进制的字符串; ntohs将无符号2字节整型  网络-->主机 */
		printf("客户端[%s : %d]连接\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));


		if (0>(pid=fork())) ERRLOG("fork error");

		else if (0==pid)	// 子进程逻辑
		{
			child_do(accept_fd,sql_db);
		}
		else	//父进程逻辑
		{
			
            /*注册信号处理函数，用于防止僵尸进程;当子进程结束的时候，父进程会收到一个SIGCHLD的信号 */
			if (signal(SIGCHLD, deal_signal) == SIG_ERR) //捕获SIGCHLD
                ERRLOG("signal error");
           close(accept_fd);
		}
	}
	
	//关闭监听套接字  一般不关闭
    close(sockfd);
	return 0;
}

// 1. 数据库初始化 ---打开数据文件、建表
sqlite3 *proc_init(void)
{
	//1. 打开数据库文件
	sqlite3 *sql_db=NULL;
	int ret=sqlite3_open(FILEname,&sql_db);
	if (ret!=SQLITE_OK)
	{
		printf("打开数据库文件 失败");
        printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
        exit(-1);
	}
	//2. 建表
    /* IF NOT EXISTS  表不存在则创建  表存在则直接使用，而不是报错;引号里面sql语句后面不用加分号*/
	//管理员-密码
	char sql_rbuf[256]="CREATE TABLE IF NOT EXISTS root(id INT PRIMARY KEY, pass TEXT)";
	ret=sqlite3_exec(sql_db,sql_rbuf,NULL,NULL,NULL);
	if (ret!=SQLITE_OK)
	{
		perror("建root表 失败");
        printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
        exit(-1);
	}
	//用户-密码-性别-年龄-住址-薪资-职务
	char sql_ubuf[256]="CREATE TABLE IF NOT EXISTS user(id INT PRIMARY KEY,pass TEXT,name TEXT,sex TEXT,age INT,pay INT,job TEXT)";
	ret=sqlite3_exec(sql_db,sql_ubuf,NULL,NULL,NULL);
	if (ret!=SQLITE_OK)
	{
		perror("建user表 失败");
        printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
        exit(-1);
	}
	
	return sql_db;
}

//3. 创建套接字-填充服务器网络信息结构体-绑定-监听
int socket_bind_listen(const char *argv[])
{
	// 1.创建套接字      /IPV4    /TCP
	int sockfd=socket(AF_INET,SOCK_STREAM,0);
	if (-1==sockfd)	ERRLOG("创建套接字 失败"); 

	// 2.填充服务器网络信息结构体
	struct sockaddr_in server_addr;
	memset(&server_addr,0,sizeof(server_addr));//清空
	server_addr.sin_family=AF_INET;			   // IPV4 
    /*端口号   atoi字符串转换成整型数; htons将无符号2字节整型  主机-->网络*/
	server_addr.sin_port=htons(atoi(argv[2]));
    /*ip地址;  inet_addr字符串转换成32位的网络字节序二进制值*/
	server_addr.sin_addr.s_addr=inet_addr(argv[1]);

	//结构体长度
	socklen_t server_addr_len=sizeof(server_addr);

	//3. 将套接字和网络信息结构体绑定
	if (-1==bind(sockfd,(struct sockaddr *)&server_addr,server_addr_len))
		ERRLOG("结构体绑定 失败"); 
	
	//4. 将套接字设置成被动监听状态
    if (-1 == listen(sockfd, 10))
        ERRLOG("listen error");
	
	return sockfd;
}

// 子进程执行
void child_do(int accept_fd, sqlite3 *sql_db)
{
	MSG msg;
	memset(&msg,0,sizeof(MSG));
    while (recv(accept_fd, &msg, sizeof(MSG), 0) > 0) // 0：阻塞；接收请求
    {
        printf("type = %d\n", msg.type); //选择
        switch (msg.type)
        {
        case R: // 1. 注册
            do_register_s(accept_fd, &msg, sql_db);
            break;
        case L: // 2. 登录
            do_login_s(accept_fd, &msg, sql_db);
            break;
        case Q: // 3. 查询
            do_query_s(accept_fd, &msg, sql_db);
            break;
        case M: // 4.修改
            do_Modify_s(accept_fd, &msg, sql_db);
			break;
		case ROOT: //ROOT 登录
            root_login_s(accept_fd, &msg, sql_db);
            break;
		case D: //删除
            root_delete_s(accept_fd, &msg, sql_db);
            break;
		case Qall: // 查询所有
            //All_query_s(accept_fd, &msg, sql_db);
			all_query_s(accept_fd,sql_db);
            break;
        }
    }
    printf("客户端 退出\n");
    exit(0);
}

// 信号处理函数  用于回收子进程资源
void deal_signal(int s)
{
	//回收子进程资源
    wait(NULL); //阻塞回收
}

// 1. 注册
void do_register_s(int accept_fd, MSG *msg, sqlite3 *sql_db)
{
	char sql_buf[512];
	memset(sql_buf,0,sizeof(sql_buf));
    //使用sqlite3_exec函数调用插入函数判断是否能够插入成功
    //由于用户名设置为主键，所以如果用户名已经存在就会报错
    //大写，小写容易报错
	sprintf(sql_buf,"INSERT INTO user(id,pass) VALUES(%d,'%s')", msg->id, msg->pass);
	int ret=sqlite3_exec(sql_db,sql_buf,NULL,NULL,NULL);
	if (ret!=SQLITE_OK)
	{
		perror("注册 失败");
		printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
		sprintf(msg->data, "ID %d 已经存在!!!", msg->id);
	}
	else
	{
		strcpy(msg->data, "注册成功");
	}
	 //发送数据
    if (0 >= send(accept_fd,msg, sizeof(MSG), 0))
        ERRLOG("send error");
}

// 2. 登录
void do_login_s(int accept_fd, MSG *msg, sqlite3 *sql_db)
{
	char sql_buf[256]={0};
	//使用查询函数判断是否存在
	sprintf(sql_buf,"SELECT * FROM user WHERE id=%d AND pass='%s'", msg->id, msg->pass);
	
	char **result;	// 结果集
	int row = 0;	// 行数
	int column = 0; // 列数
					/*
					会将 查询的到的结果的 行数写到row的地址里  列数写到column的地址里
					让 result 指向 sqlite3_get_table 申请的结果集的内存空间
					*/
	//查询结果的函数                             /结果集   /行数  /列数   /错误信息
	int ret=sqlite3_get_table(sql_db,sql_buf,&result,&row,&column,NULL);
	if (ret!=SQLITE_OK)
	{
		perror("查询 失败");
		printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
	}
	if (0==row)
	{
		sprintf(msg->data,"ID[%d]与密码[%s]不一致", msg->id,msg->pass);
	}
	else
    {
        strcpy(msg->data, "登录成功");
    }
	//发送数据
    if (0 >= send(accept_fd, msg, sizeof(MSG), 0))
        ERRLOG("send error");
}

// 3. 查询
void do_query_s(int accept_fd, MSG *msg, sqlite3 *sql_db)
{
	int id=msg->id;
	memset(msg,0,sizeof(MSG));
	msg->id=id;
	//printf("查询ID:%d\n",msg->id);
	char sql_buf[256]={0};
	
	//使用查询函数
	sprintf(sql_buf,"SELECT * FROM user WHERE id=%d",msg->id);
	char **result={0};	// 结果集
	int row = 0;	// 行数
	int column = 0; // 列数
					/*
					会将 查询的到的结果的 行数写到row的地址里  列数写到column的地址里
					让 result 指向 sqlite3_get_table 申请的结果集的内存空间
					*/
	//查询结果的函数                             /结果集   /行数  /列数   /错误信息
	int ret=sqlite3_get_table(sql_db,sql_buf,&result,&row,&column,NULL);
	if (ret!=SQLITE_OK)
	{
		perror("查询 失败");
		printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
	}
	if (0==row)
	{
		sprintf(msg->data,"ID[%d]为空", msg->id);

	}
	else
    {
		if (result[column])
		{
			msg->id=atoi(result[column]);
		}
		//上输入的字符个数大于s的大小的时候，最多格式化sizeof(s)-1个字符，在s最后一个字符的
		//位置补上'\0'
		snprintf(msg->pass,sizeof(msg->pass),"%s",result[column+1]);
		snprintf(msg->name,sizeof(msg->name),"%s",result[column+2]);
		snprintf(msg->sex,sizeof(msg->sex),"%s",result[column+3]);
		if (result[column+4])
		{
			msg->age=atoi(result[column+4]);
		}
		if (result[column+5])
		{
			msg->pay=atoi(result[column+5]);
		}
		snprintf(msg->job,sizeof(msg->job),"%s",result[column+6]);
	}
	//发送数据
    if (0 >= send(accept_fd,msg, sizeof(MSG), 0))
        ERRLOG("send error");
	//释放 结果集 防止内存泄漏
	sqlite3_free_table(result);
}

// 4. 修改
void do_Modify_s(int accept_fd, MSG *msg, sqlite3 *sql_db)
{
	char sql_buff[512] = {0};
	// pass ,name ,sex ,age,pay,job
	sprintf(sql_buff,"UPDATE user SET pass='%s',name='%s',sex='%s',age=%d,pay=%d,job='%s' WHERE id=%d",
					msg->pass,msg->name,msg->sex,msg->age,msg->pay,msg->job,msg->id);
	//执行sql语句
	int ret = sqlite3_exec(sql_db, sql_buff, NULL, NULL, NULL);
	if (ret != SQLITE_OK)
	{
		perror("修改 失败");
		printf("返回值[%d]  错误信息[%s]\n", ret, sqlite3_errmsg(sql_db));
		exit(-1);
	}
	strcpy(msg->data, "修改成功");
	//发送数据
    if (0 >= send(accept_fd,msg, sizeof(MSG), 0))
        ERRLOG("send error");
	memset(msg,0,sizeof(MSG));
}


// 5. ROOT登录
void root_login_s(int accept_fd, MSG *msg, sqlite3 *sql_db)
{
	char sql_buf[256]={0};
	//使用查询函数判断是否存在
	sprintf(sql_buf,"SELECT * FROM root WHERE id=%d AND pass='%s'",123456, msg->pass);
	
	char **result;	// 结果集
	int row = 0;	// 行数
	int column = 0; // 列数
					/*
					会将 查询的到的结果的 行数写到row的地址里  列数写到column的地址里
					让 result 指向 sqlite3_get_table 申请的结果集的内存空间
					*/
	//查询结果的函数                             /结果集   /行数  /列数   /错误信息
	int ret=sqlite3_get_table(sql_db,sql_buf,&result,&row,&column,NULL);
	if (ret!=SQLITE_OK)
	{
		perror("查询 失败");
		printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
	}
	if (0==row)
	{
		sprintf(msg->data,"ID[%d]与密码[%s]不一致", msg->id,msg->pass);
	}
	else
    {
        strcpy(msg->data, "登录成功");
    }
	//发送数据
    if (0 >= send(accept_fd, msg, sizeof(MSG), 0))
        ERRLOG("send error");
	memset(msg,0,sizeof(MSG));
}

//6. 删除
void root_delete_s(int accept_fd, MSG *msg, sqlite3 *sql_db)
{
	char sql_buf[256]={0};
	//填写sql语句
	sprintf(sql_buf,"DELETE FROM user WHERE id=%d",msg->id);
	//执行sql语句
	int ret = sqlite3_exec(sql_db, sql_buf, NULL, NULL, NULL);
	if (ret!=SQLITE_OK)
	{
		perror("查询 失败");
		printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
	}
	else
    {
        strcpy(msg->data, "删除成功");
    }
	//发送数据
    if (0 >= send(accept_fd, msg, sizeof(MSG), 0))
        ERRLOG("send error");
	memset(msg,0,sizeof(MSG));
}

// 7. 查询所有
void all_query_s(int accept_fd,sqlite3 *sql_db)
{
	MSG msg;
	int i,x;
	char sql_buf[256]={0};
	memset(&msg,0,sizeof(msg));
	//使用查询函数
	strcpy(sql_buf,"SELECT * FROM user");
	char **result;	// 结果集
	int row = 0;	// 行数
	int column = 0; // 列数
					/*
					会将 查询的到的结果的 行数写到row的地址里  列数写到column的地址里
					让 result 指向 sqlite3_get_table 申请的结果集的内存空间
					*/
	//查询结果的函数                             /结果集   /行数  /列数   /错误信息
	int ret=sqlite3_get_table(sql_db,sql_buf,&result,&row,&column,NULL);
	if (ret!=SQLITE_OK)
	{
		perror("查询 失败");
		printf("errcode[%d]  errmsg[%s]\n", ret, sqlite3_errmsg(sql_db));
	}
	if (0==row)
	{
		sprintf(msg.data,"ID[%d]为空", 0);
	}
	else
    {
		x=column;
		for (i= 0; i<row; i++)// 行数
		{
			if (result[x])
			{
				msg.id=atoi(result[x]);
			}
			//上输入的字符个数大于s的大小的时候，最多格式化sizeof(s)-1个字符，在s最后一个字符的
			//位置补上'\0'
			x++;
			snprintf(msg.pass,sizeof(msg.pass),"%s",result[x++]);
			snprintf(msg.name,sizeof(msg.name),"%s",result[x++]);
			snprintf(msg.sex,sizeof(msg.sex),"%s",result[x++]);
			if (result[x])
			{
				msg.age=atoi(result[x]);
			}
			x++;
			if (result[x])
			{
				msg.pay=atoi(result[x]);
			}
			x++;
			snprintf(msg.job,sizeof(msg.job),"%s",result[x++]);
			//发送数据
			if (0 >= send(accept_fd,&msg, sizeof(MSG), 0))
				ERRLOG("send error");
			memset(&msg,0,sizeof(msg));
			if (row==(i+1))
			{
				strcpy(msg.data,"**over**");
				//发送数据
				if (0 >= send(accept_fd,&msg, sizeof(MSG), 0))
					ERRLOG("send error");
			}				
		}	
	}
	//释放 结果集 防止内存泄漏
	sqlite3_free_table(result);
}